package classificator.server;

import classificator.data.Data;
import classificator.data.DataException;
import classificator.tree.DecisionTree;
import classificator.tree.LeafNode;
import classificator.tree.SplitNode;
import classificator.tree.UnknownValueException;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import java.net.Socket;

/**gestisce la connessione col singolo client
 *
 * @author Administrator
 */
class ServerOneClient extends Thread {
    private Socket socket;
    // stream con richieste del client
    private ObjectInputStream in; 
    // stream con risposte per client
    private ObjectOutputStream out;
    private DecisionTree tree;
    private String nomeFile;

    public ServerOneClient(Socket s) throws IOException {
        socket = s;
        in = new ObjectInputStream(socket.getInputStream());
        out = new ObjectOutputStream(socket.getOutputStream());
        start(); // Chiama run()
    }

    @Override
    public void run() {
        System.out.println("Nuovo client connesso");
        System.out.println(socket.getInetAddress().getHostName());
        System.out.println(socket.getLocalAddress().getHostName());
        try {
            while (true) {
                try{
                    Object read = in.readObject();
                    int command = Integer.parseInt(read.toString().substring(0, 1));
                    switch(command){
                        case 1: 
                            String name = read.toString().substring(1); //nome tabella
                        //TODO: LEARNING A DECISION TREE
                            try {
                                
                                tree = new DecisionTree(new Data(name)); 
                                out.writeObject("Learning DT...");
                                
                                tree.printRules();
                                out.writeObject("********* TREE **********");
                                out.writeObject(tree.toString());
                                out.writeObject("*************************");
                                
                            } catch (DataException ex) {
                                out.writeObject(ex);
                                ex.printStackTrace();
                            } finally{
                                break;
                            }
                        case 2: //TODO: SERIALIZE THE CURRENT DECISION TREE ON A FILE
                            try {
                                out.writeObject("Saving current DT into file...");
                                out.writeObject("ciao...");
                                //tree.salva(nomeFile);
                                //System.out.println("tree.dat salvato");
                            } catch (FileNotFoundException ex) {
                                ex.printStackTrace();
                            } catch (IOException ex) {
                                ex.printStackTrace();
                            } finally{
                                break;
                            }
                        case 3: //TODO: STORE THE DECISION TREE FROM FILE
                            try {
                                out.writeObject("Store DT from file...");
                                out.writeObject("ciao...");
                                //tree.salva(nomeFile);
                                //System.out.println("tree.dat salvato");
                            } catch (FileNotFoundException ex) {
                                ex.printStackTrace();
                            } catch (IOException ex) {
                                ex.printStackTrace();
                            } finally{
                                break;
                            }
                        case 4: //USE THE CURRENT TREE TO PREDICT AN EXAMPLE
                            try {
                                out.writeObject("Transmitting class ...");
                                String classValue = predictClass(tree);
                                out.writeObject("CLASSE:" + classValue);
                            } catch (NullPointerException e) {
                                System.out.println("Prediction: Albero non esistente");
                                out.writeObject("Prediction: Albero non esistente");
                            } catch(UnknownValueException e){
                                System.out.println("Prediction: Opzione scelta inesistente");
                                out.writeObject("Prediction: Opzione scelta inesistente");
                            } finally{
                                break;
                            }
                        default:
                            System.out.println("COMANDO INESISTENTE");
                            out.writeObject("COMANDO INESISTENTE");
                    }// END SWITCH
                }
                catch(IOException e){
                    e.printStackTrace();
                } 
                catch(ClassNotFoundException e){
                    e.printStackTrace();
                }
            }//end while
        } finally {
            try {
                socket.close();
                System.out.println("Socket chiuso!");
            } catch (IOException e) {
                System.out.println("Socket non chiuso!");
            }
        }
    }
	
    /**Visualizza le informazioni di ciascuno split dell'albero 
     * e per il corrispondente attributo acquisisce il valore dell'esempio da classificare da tastiera. 
     * 
     * Se il nodo root corrente è una foglia/leaf termina l'acquisizione e visualizza la classe, 
     * altrimenti invoca ricorsivamente sul figlio di root in childTree[] individuato 
     * dal valore acquisito da tastiera
     * 
     * @return Stringa contenente il valore di classe (YES/NOI) dell'esempio inserito. 
     */
    private String predictClass(DecisionTree tree)throws UnknownValueException, 
                                            ClassNotFoundException, IOException{
        if(tree.getRoot() instanceof LeafNode)
            return ((LeafNode) tree.getRoot()).getPredictedClassValue();
        else {
            int risp;
            out.writeObject((((SplitNode)tree.getRoot()).formulateQuery()));
            risp=((Integer)in.readObject()).intValue();
            if(risp == -1 || risp >= tree.getRoot().getNumberOfChildren())
                throw new UnknownValueException();
            else
                return predictClass(tree.subTree(risp));
        }
    }   
}